package org.glavo.bot

import kotlinx.serialization.json.*
import net.mamoe.mirai.contact.nameCardOrNick
import net.mamoe.mirai.event.events.MessageEvent
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.message.data.MessageSource.Key.quote
import org.glavo.bot.data.Config
import org.glavo.bot.data.Player
import java.lang.IllegalArgumentException
import java.lang.StringBuilder
import java.util.regex.Pattern

private val sayPattern = Pattern.compile("(?<name>$NamePattern): ")

private val colorJson = buildJsonObject {
    put("text", "")
    put("color", "#d3d3d3")
}

suspend fun forward(event: MessageEvent, message: MessageChain, auto: Boolean = true, rmPre: Boolean = false): Boolean {
    var mutableRePre = rmPre
    val tem = mutableListOf<JsonElement>()

    val player = Player[event.sender.id]
    val playerName = player?.names?.firstOrNull().let {
        if (it == null) event.sender.nameCardOrNick else "$it"
    }
    val atCommand = "@" + (player?.names?.firstOrNull() ?: event.sender.id) + " "
    val card = player?.names?.firstOrNull().let {
        if (it == null) {
            "@${event.sender.nameCardOrNick}(${event.sender.id})"
        } else {
            "@$it"
        }
    }
    tem += colorJson
    tem += buildJsonObject {
        put("text", "<$playerName>")
        putJsonObject("hoverEvent") {
            put("action", "show_text")
            put("contents", card)
        }
        put("insertion", atCommand)
        putJsonObject("clickEvent") {
            put("action", "suggest_command")
            put("value", atCommand)
        }
    }
    tem += JsonPrimitive(" ")

    val qr = message[QuoteReply]
    if (qr != null) {
        val fromId = qr.source.fromId
        val name = if (fromId == Config.qq) {
            val m = sayPattern.matcher(qr.source.originalMessage.content)
            if (m.lookingAt()) {
                m.group("name")!!
            } else {
                "喵呜呜二号"
            }
        } else {
            Player.nameOf(fromId) ?: MainGroup[fromId]?.nameCardOrNick ?: fromId.toString()
        }

        tem += JsonPrimitive("(回复 $name) ")
    }

    val builder = StringBuilder()

    loop@
    for (m in message) {
        when (m) {
            is PlainText -> {
                var c = m.content
                if (mutableRePre) {
                    mutableRePre = false
                    if (c.startsWith('>') || c.startsWith('＞')) {
                        if (c.length <= 1) {
                            continue@loop
                        }
                        c = c.substring(1)

                    }
                }
                c = c.replace("\r\n", "\n")
                c = c.replace('\r', '\n')
                builder.append(c)
            }
            is At -> builder.append(Player[m.target]?.names?.firstOrNull()?.let { "@$it" }
                ?: m.getDisplay(MainGroup))
            is Image -> {
                if (m.isEmoji) {
                    builder.append("[动画表情]")
                } else {
                    if (builder.isNotEmpty()) {
                        tem += JsonPrimitive(builder.toString())
                        builder.clear()
                    }
                    tem += m.asJson()
                }
            }
            is LightApp -> builder.append("[小程序消息]")
            is ServiceMessage -> builder.append("[服务消息]")
            else -> builder.append(m.content)
        }
    }

    if (builder.isNotEmpty()) {
        tem += JsonPrimitive(builder.toString())
        builder.clear()
    }

    try {
        when (tem.size) {
            0 -> {
            }
            1 -> rcon("tellraw @a " + tem.first())
            else -> rcon("tellraw @a " + JsonArray(tem))
        }
    } catch (e: Throwable) {
        if (!auto) {
            if (e is IllegalArgumentException && e.message == "Payload too long") {
                event.subject.sendMessage(event.message.quote() + "消息过长，无法发送")
            } else {
                event.subject.sendMessage(event.message.quote() + "连接服务器失败")
            }
        }
    }

    return true
}